#include "NguyenWidrowFunction.h"
#include <math.h>
#include "../Backpropagation/BackpropagationSynapse.h"
#include "../Backpropagation/ActivationNeuron.h"
#include "../Helper.h"

using namespace NeuralPlusPlus::Core;

NeuralPlusPlus::Core::Initializers::NguyenWidrowFunction::NguyenWidrowFunction( double outputRange /*=1*/ )
	{
	this->OutputRange = outputRange;
	}

void NeuralPlusPlus::Core::Initializers::NguyenWidrowFunction::Initialize( Layer *activationLayer )
	{
	Helper::ValidateNotNull(activationLayer, "activationLayer");
	int hiddenNeuronCount = 0;
	int targetConnectorSize = activationLayer->TargetConnectors.size();
	for (int i=0;i<targetConnectorSize;i++)
		{
		Connector *targetConnector = activationLayer->TargetConnectors[i];
		hiddenNeuronCount += targetConnector->TargetLayer->NeuronsLength;
		}

	double nGuyenWidrowFactor = NGuyenWidrowFactor(activationLayer->NeuronsLength, hiddenNeuronCount);
	for (int i=0;i<activationLayer->NeuronsLength;i++)
		{
		((ActivationNeuron*)(*activationLayer)[i])->Bias = Helper::GetRandom(-nGuyenWidrowFactor, nGuyenWidrowFactor);
		}
	}

void NeuralPlusPlus::Core::Initializers::NguyenWidrowFunction::Initialize( Connector *connector )
	{
	Helper::ValidateNotNull(connector, "connector");

	double nGuyenWidrowFactor = NGuyenWidrowFactor(
		connector->SourceLayer->NeuronsLength, connector->TargetLayer->NeuronsLength);
	int synapsesPerNeuron = connector->SynapsesLength / connector->TargetLayer->NeuronsLength;

	for (int i=0;i<connector->TargetLayer->NeuronsLength;i++)
		{
		double *normalizedVector = Helper::GetRandomVector(synapsesPerNeuron, nGuyenWidrowFactor);

		Layer *targetLayer = connector->TargetLayer;
		std::vector<ISynapse*> *sourceSynapses = connector->GetSourceSynapses((*targetLayer)[i]);

		int index = 0;
		int sourceSynapsesSize = sourceSynapses->size();
		for(int j=0;j<sourceSynapsesSize;j++)
			{
			ISynapse *synapse = (*sourceSynapses)[j];
			synapse->Weight = normalizedVector[index];
			}
		delete sourceSynapses;
		delete[] normalizedVector;

		}
	}

double NeuralPlusPlus::Core::Initializers::NguyenWidrowFunction::NGuyenWidrowFactor( int inputNeuronCount, int hiddenNeuronCount )
	{
	return 0.7 * pow((double)hiddenNeuronCount, (1.0 / (double)inputNeuronCount)) / OutputRange;
	}